//
// Created by liyuzhao on 11/2/22.
//

#include "simpledemo.h"
#include <iostream>
#include <memory>
#include <chrono>
#include <thread>
#include <emchatmanager_interface.h>
#include <message/emtextmessagebody.h>
#include <emcallback.h>
#include <emclient.h>
#include <emlogininfo.h>
#include <sstream>


using namespace std;
using namespace easemob;

class ConnectionListener : public easemob::EMConnectionListener {

public:
    ConnectionListener() = default;
    virtual void onConnect(const std::string& info = "") { cout << "---> connected:" << info << endl; }
    virtual void onDisconnect(EMErrorPtr error) {
        if (error->mErrorCode == EMError::USER_LOGIN_ANOTHER_DEVICE) {
            cerr << "---> was kicked out" << endl;
        }
    }
};


class ChatListener : public EMChatManagerListener {
public:
    ChatListener() = default;

    virtual void onReceiveMessages(const EMMessageList& messages);
    virtual void onReceiveCmdMessages(const EMMessageList& messages);

private:
    EMCallbackObserverHandle m_coh;
    void onTextMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType);
    void onFileMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType);
    void onImageMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType);
    void onVoiceMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType);
    void onVideoMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType);
    void onLocationMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType);
};

void ChatListener::onReceiveCmdMessages(const EMMessageList& messages)
{

}

void ChatListener::onReceiveMessages(const EMMessageList& messages)
{

    for (EMMessagePtr msg : messages)
    {
        EMMessage::EMChatType type = msg->chatType();
        string sChatType = "chat";
        if (type == EMMessage::GROUP)
        {
            sChatType = "groupchat";
        }
        else if (type == EMMessage::CHATROOM)
        {
            sChatType = "chatroom";
        }
        const vector<EMMessageBodyPtr>& bodies = msg->bodies();
        const EMMessageBodyPtr _body = bodies[0];
        switch (_body->type())
        {
            case EMMessageBody::TEXT:
            {
                onTextMessage(msg, _body, sChatType);
                break;
            }
            case EMMessageBody::FILE:
            {
                onFileMessage(msg, _body, sChatType);
                break;
            }
            case EMMessageBody::IMAGE:
            {
                onImageMessage(msg, _body, sChatType);
                break;
            }
            case EMMessageBody::VOICE:
            {
                onVoiceMessage(msg, _body, sChatType);
                break;
            }
            case EMMessageBody::VIDEO:
            {
                onVideoMessage(msg, _body, sChatType);
                break;
            }
            case EMMessageBody::LOCATION:
            {
                onLocationMessage(msg, _body, sChatType);
                break;
            }
            case EMMessageBody::COMMAND:
                break;
            case EMMessageBody::CUSTOM:
                break;
        }
    }
}

void ChatListener::onTextMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType)
{
    cout << "received onTextMessage" << endl;

    EMTextMessageBodyPtr body = std::dynamic_pointer_cast<EMTextMessageBody, EMMessageBody>(_body);
    std::stringstream stream;
    stream << "Demo.conn.onTextMessage('{id: \"";
    stream << msg->msgId();
    stream << "\",type : \"";
    stream << sChatType;
    stream << "\", from : \"";
    stream << msg->from();
    stream << "\",to : \"";
    stream << msg->to();
    stream << "\",data : \"";
    stream << body->text();
    stream << "\",ext : \"\"}');";

    cout << stream.str() << endl;

}
void ChatListener::onFileMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType)
{}

void ChatListener::onImageMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType)
{}
void ChatListener::onVoiceMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType)
{}
void ChatListener::onVideoMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType)
{}
void ChatListener::onLocationMessage(const EMMessagePtr msg, const EMMessageBodyPtr _body, string sChatType)
{}


void SimpleDemo::testSendMessage() {

    auto* listener = new ConnectionListener();
    mClient->addConnectionListener(listener);


    createTestAccount();

    easemob::EMErrorPtr retPtr = mClient->login(TestAccounts[0], "123456");
    if (retPtr->mErrorCode == EMError::EM_NO_ERROR) {
        std::cout << "login success!" << std::endl;
    }
    else {
        std::cerr << "login failed!" << retPtr->mErrorCode << std::endl;
    }

    EMCallbackObserverHandle handle;

    auto* mChatListener = new ChatListener();
    mClient->getChatManager().addListener(mChatListener);

    if (retPtr->mErrorCode == EMError::EM_NO_ERROR) {
        EMMessageBodyPtr body = EMTextMessageBodyPtr(new EMTextMessageBody("hello world with txt type"));
        EMMessage::EMChatType chatType = EMMessage::SINGLE;

        //创建待发消息
        EMMessagePtr msg = EMMessage::createSendMessage(mClient->getLoginInfo().loginUser(), TestAccounts[1], body, chatType);

        EMCallbackPtr msgCallback(new EMCallback(handle,
                                                 [=](void)->bool {
                                                     cout << "send message sucess!" << endl;
                                                     return true;
                                                 },
                                                 [=](const easemob::EMErrorPtr ePtr)->bool
                                                 {
                                                     cout << "send message failed!" << ePtr->mErrorCode << endl;
                                                     return false;
                                                 },
                                                 [](int progress) {}));

        msg->setCallback(msgCallback);
        mClient->getChatManager().sendMessage(msg);
    }

    cout << "wait message callback" << endl;
    EMError error;
    EMCursorResultRaw<EMMessagePtr> cursorResult = mClient->getChatManager().fetchHistoryMessages(TestAccounts[1],EMConversation::EMConversationType::CHAT, error, 20, "");

    if (error.mErrorCode == EMError::EM_NO_ERROR) {
        std::cout << "fetch history success!" << std::endl;
        vector<EMMessagePtr> messages = cursorResult.result();
        string nextCursor = cursorResult.nextPageCursor();
        cout << "nextCursor -> " << nextCursor << endl;
        cout << "fetch history size: " << messages.size() << endl;
        for(EMMessagePtr item : messages) {
            cout << "msg from:" << item->from() << ", to:" << item->to() << ", type:" << item->chatType() << ",id:" << item->msgId() << endl;
        }
    } else {
        std::cout << "fetch history fail!" << error.mErrorCode << std::endl;
    }


    std::this_thread::sleep_for(std::chrono::milliseconds(30000));

    cout << "will release mClient" << endl;
    mClient->getChatManager().removeListener(mChatListener);
    mClient->removeConnectionListener(listener);
    mClient->logout();

    delete listener;
    delete mClient;
}